var MongoClient = require('mongodb').MongoClient;
var EventEmitter = require('events').EventEmitter;

//获取出历史数据版本的名字
fs.smartMkfileSync(__dirname + "/.db/mongodb_names." + database_name + ".json", "[]");
var col_names = require("./.db/mongodb_names." + database_name + ".json");
var col_name = col_names[0];

var connect = function() {
    var fiber = Fiber.current;
    var _err;
    var _res;
    MongoClient.connect('mongodb://127.0.0.1:27017/' + col_name, function(err, db) {
        _err = err;
        _res = db;
        fiber.run();
    });
    Fiber.yield(); //挂起
    if (_err) {
        Throw(_err);
    }
    return _res
};

var mon_db = {
    _isConnectAble: function() {
        try {
            var db = connect();
            return true;
        } catch (e) {
            return false;
        }
    },
    _updateCache: function(fileName) { //更新缓存到文件中进行备份
        var db = connect();
        var fiber = Fiber.current;
        var _err;
        var _res;
        db.collectionNames(function(err, names) {
            _err = err;
            _res = names;
            db.close();
            fiber.run();
        });
        Fiber.yield(); //挂起
        if (_err) {
            Throw(_err);
        }
        var _db = {};
        _res.forEach(function(item) {
            var name = item.name.substr(col_name.length + 1);
            if (name !== "system.indexes") {
                _db[name] = mon_db.find_all(name);
            }
        });
        console.time("update_data");
        var _data = JSON._stringify(_db)
        if (_data) {
            fileName || (fileName = "data.bak." + (new Date).format("yyyy_MM_dd_HH_mm") + ".json");
            require("fs").writeFileSync(__dirname + "/.db/" + fileName, _data);
        }
        console.timeEnd("update_data");
    },
    _getCollection: function(db_name) {
        db_name = db_name.toLowerCase();
        var db = connect();
        var col = db.collection(db_name);
        col.close = function() {
            db.close()
        };
        return col;
    },
    insert: function(db_name, obj, index) {
        var collection = mon_db._getCollection(db_name);
        var fiber = Fiber.current;
        var _err;
        obj._id || (obj._id = index);
        if (mon_db.find_by_id(db_name, obj._id)) { //如果已经是有存在的数据了转为使用update
            collection.close();
            mon_db.update(db_name, obj._id, obj);
            return;
        }
        // console.log("INSERT:", obj);
        collection.insert(obj, function(err, result) {
            // console.log(result);
            mon_db.emit("insert", db_name.toLowerCase(), obj);
            _err = err;
            fiber.run();
        });
        Fiber.yield(); //挂起
        collection.close();
        if (_err) {
            Throw(_err);
        }
    },
    find_by_id: function(db_name, id) {
        var collection = mon_db._getCollection(db_name);
        var fiber = Fiber.current;
        var _err;
        var _res;
        collection.findOne({
            _id: id
        }, function(err, result) {
            _err = err;
            _res = result;
            fiber.run();
        });
        Fiber.yield(); //挂起
        collection.close();
        if (_err) {
            Throw(_err);
        }
        return _res;
    },
    find_one: function(db_name, obj) {
        var collection = mon_db._getCollection(db_name);
        var fiber = Fiber.current;
        var _err;
        var _res;
        collection.findOne(mon_db._obj_flat(obj), function(err, result) {
            _err = err;
            _res = result;
            fiber.run();
        });
        Fiber.yield(); //挂起
        collection.close();
        if (_err) {
            Throw(_err);
        }
        return _res;
    },
    find_last_one: function(db_name, obj, sort_key, no_asc) {
        var collection = mon_db._getCollection(db_name);
        var fiber = Fiber.current;
        var _err;
        var _res;
        var _sort = {};
        //升序为1，倒序为-1，默认为倒序：大>小
        _sort[sort_key] = (!no_asc) ? -1 : 1;
        collection.find(mon_db._obj_flat(obj)).sort(_sort).toArray(function(err, result) {
            _err = err;
            _res = result[0];
            fiber.run();
        });
        Fiber.yield(); //挂起
        collection.close();
        if (_err) {
            Throw(_err);
        }
        return _res;
    },
    find_list: function(db_name, obj, num) {
        var collection = mon_db._getCollection(db_name);
        var fiber = Fiber.current;
        var _err;
        var _res;
        collection.find(mon_db._obj_flat(obj)).toArray(function(err, result) {
            _err = err;
            _res = result;
            fiber.run();
        });
        Fiber.yield(); //挂起
        collection.close();
        if (_err) {
            Throw(_err);
        }
        return _res;
    },
    find_all: function(db_name) {

        return mon_db.find_list(db_name, {});
    },
    update: function(db_name, obj_index, obj) {
        var collection = mon_db._getCollection(db_name);
        var fiber = Fiber.current;
        var _err;
        var _res
        var _id_bak;
        (_id_bak = obj._id) && (delete obj._id); //UPDATE 命令不能有ID在，临时删除
        collection.update({
            _id: obj_index
        }, {
            $set: obj
        }, function(err, result) {
            _err = err;
            _res = result;
            fiber.run();
        });
        Fiber.yield(); //挂起
        collection.close();
        if (_err) {
            Throw(_err);
        }
        //还原ID
        obj._id = _id_bak;
        if (_res === 0) {
            console.log("修改", db_name, obj_index, "时，0行受影响，转成插入模式");
            mon_db.insert(db_name, obj, obj_index);
        }
    },
    remove: function(db_name, obj_index) {
        var collection = mon_db._getCollection(db_name);
        var fiber = Fiber.current;
        var _err;
        collection.remove({
            _id: obj_index
        }, function(err, result) {
            _err = err;
            if (result === 0) {
                console.info("要移除的对象不存在：", db_name, obj_index);
            }
            fiber.run();
        });
        Fiber.yield(); //挂起
        collection.close();
        if (_err) {
            Throw(_err);
        }
    },
    remove_list: function(db_name, obj) {
        var collection = mon_db._getCollection(db_name);
        var fiber = Fiber.current;
        var _err;
        collection.remove(obj, function(err, result) {
            _err = err;
            if (result === 0) {
                console.info("要移除的对象不存在：", db_name, obj);
            }
            fiber.run();
        });
        Fiber.yield(); //挂起
        collection.close();
        if (_err) {
            Throw(_err);
        }
    },
    refreshIndex: function(fileName) {
        fileName || (fileName = "data.cache." + database_name + ".json");
        //如果存在文件版本的数据库，则使用这个数据库，并导入到新的数据集
        if (fs.existsSync(__dirname + "/.db/" + fileName) && !fs.existsSync(__dirname + "/.db/.file.db.lock")) {
            console.log("发现文件版数据库");
            var _db = require("./.db/" + fileName);
            col_name = database_name + "_" + (new Date).format("YYYY_MM_dd_HH_mm");
            console.log("使用新的数据集：", col_name);
            col_names.unshift(col_name);
            fs.writeFileSync(__dirname + "/.db/mongodb_names." + database_name + ".json", JSON.stringify(col_names));
            console.log("开始录入文件数据");
            for (var db_name in _db) {
                if (_db.hasOwnProperty(db_name)) {
                    //并不会触发对应的emit事件，因为db还没有exports出去，不会有注册的事件
                    console.log("表", db_name, "录入，共", _db[db_name].length, "条数据");
                    mon_db.insert(db_name, _db[db_name])
                }
            }
            // fs.renameSync(__dirname + "/.db/data.cache.json", __dirname + "/.db/data.cache.to_" + col_name + ".json")
            fs.writeFileSync(__dirname + "/.db/.file.db.lock", "");
        } else {
            console.log("使用现有数据集：", col_name);
        }
    },
    bak: function() {
        //文件备份
        fs.renameSync(__dirname + "/.db/data.cache.json", __dirname + "/.db/data.cache.to_" + database_name + "_" + (new Date).format("yyyy_MM_dd_HH_mm") + ".json")
        mon_db._updateCache("data.cache.json");
    },
    removeLock: function() {
        fs.unlinkSync(__dirname + "/.db/.file.db.lock");
    },
    _sortBy: require("./skill").sortBy,
    _obj_flat: function(obj) {
        var result = {};
        for (var i in obj) {
            var v = obj[i];
            if (typeof v === "object" && !Array.isArray(v)) {
                var _flat_v = mon_db._obj_flat(v);
                for (var ii in _flat_v) {
                    result[i + "." + ii] = _flat_v[ii];
                }
            } else {
                result[i] = v
            }
        }
        return result;
    }
};

mon_db.__proto__ = EventEmitter.prototype;
EventEmitter.call(mon_db);
module.exports = mon_db;